﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
using System.Web.UI;
using System.Web.UI.WebControls;
using GPC_Overlay;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.StorageClient;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using cloudMPI;

namespace GISWebRole
{
    public static class Msgcount
    {
        public  static int messageCount { get; set; }
    }
    public partial class _Default : System.Web.UI.Page
    {
        private enum BalancingScheme { None, LargestFirst, RowOrder, ColumnOrder }
        private string _map1;
        private string _map2;
        private string _op;
        private GpcOperation _operator;
        public Microsoft.WindowsAzure.Storage.CloudStorageAccount _account;
        public string connectionString;
        public static int concurrencyLimit = 8;
        public static int currentOps = 0;
        public static int processed = 0;
        public static int toprocess = 0;
        public static List<string> blobs;
        public static List<Polygon> basePoly;
        public static List<Polygon> overlayPoly;
        private static List<string> results = new List<string>();
        private static int numMessages = 0;
        bool processing = false;
        //cMPI mpi;

        public TimeSpan fileDownloadTime = new TimeSpan(0, 0, 0); /* Time to download files from cloud storage */
        public TimeSpan parseTime = new TimeSpan(0, 0, 0); /* time to download files and parse them into C# objects */
        public TimeSpan graphCreation = new TimeSpan(0, 0, 0);/* Time to create intersection graph */
        public TimeSpan totalTaskCreationTime = new TimeSpan(0, 0, 0); /* Time to convert each task to XML and writing it to Cloud storage */
        public TimeSpan taskUploadingTime = new TimeSpan(0, 0, 0); /* Time to write tasks to cloud storage */
        public TimeSpan taskDownloadingTime = new TimeSpan(0, 0, 0); /* Time to download tasks for processing from cloud */
        public TimeSpan processingTime = new TimeSpan(0, 0, 0); /* time to download a task, convert to polygons, and process using third party library */
       

        protected void Page_Load(object sender, EventArgs e)
        {
            connectionString = RoleEnvironment.GetConfigurationSettingValue("DataConnectionString");
            _account = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(connectionString);
            if (!IsPostBack)
            {
                GPC_Overlay.BlobHelper blobObject = new GPC_Overlay.BlobHelper(connectionString);
                _setupDropDownLists(blobObject);
            }
        }

        private void _setupDropDownLists(GPC_Overlay.BlobHelper blobObject)
        {

            CloudBlobContainer container = blobObject.BlobClient.GetContainerReference(GPC_Overlay.DataConstants.MAP_CONTAINER_BLOB);
            CloudBlobDirectory dir = container.GetDirectoryReference("./");
            List<string> maps = (from map in dir.ListBlobs() select Path.GetFileName(map.Uri.AbsolutePath)).ToList();
            List<string> maps2 = (from map in maps select map).ToList();

            Array ops = Enum.GetValues(typeof(GpcOperation));

            Array schemes = Enum.GetValues(typeof(BalancingScheme));

            foreach (string filename in maps)
            {
                ddlMap1.Items.Add(filename);
                ddlMap2.Items.Add(filename);
            }
            foreach (object op in ops)
            {
                ddlOperator.Items.Add(op.ToString());
            }
        }

        public string Overlay(string map1, string map2, string op)
        {
            string rslt = _saveResult();
            System.Diagnostics.Trace.WriteLine("GISWebRole done overlay Job" + DateTime.Now.ToString(), "Information");
            System.Diagnostics.Trace.WriteLine("Result:" + rslt, "Information");
            return rslt;
        }

        public void assignWork()
        {
            string connectionString = RoleEnvironment.GetConfigurationSettingValue("DataConnectionString");
            GPC_Overlay.BlobHelper blobObject = new GPC_Overlay.BlobHelper(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"));
            GPC_Overlay.QueueHelper QueueObject = new GPC_Overlay.QueueHelper(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"));
            StringBuilder result = new StringBuilder();
            blobObject.DeleteBlob(GPC_Overlay.DataConstants.MAP_CONTAINER_BLOB, "result.xml");
            /* Write the start of XML doc */
            result.AppendLine("<gml:FeatureCollection");
            result.AppendLine(" xmlns:gml=" + '"' + "http://www.opengis.net/gml" + '"');
            result.AppendLine(" xmlns:xlink=" + '"' + "http://www.w3.org/1999/xlink" + '"');
            result.AppendLine(" xmlns:xsi=" + '"' + "http://www.w3.org/2001/XMLSchema-instance" + '"');
            result.AppendLine(" xmlns:fme=" + '"' + "http://www.safe.com/gml/fme" + '"');
            result.AppendLine(" xsi:schemaLocation=" + '"' + "http://www.safe.com/gml/output.xsd>" + '"');
            GPC_Overlay.BlobHelper.PutBlock(connectionString, GPC_Overlay.DataConstants.MAP_CONTAINER_BLOB, GPC_Overlay.DataConstants.OUTPUT_BLOB, Guid.NewGuid().ToString(), result.ToString());
            //QueueObject.PutMessage(GPC_Overlay.DataConstants.INPUT_PARAS, new CloudQueueMessage(_map1 + "{" + _map2 + "{" + _op));
            cMPI mpi = new cMPI(connectionString, "Master");
            mpi.Init(0, 0, "input");
            cMPI_Message message = new cMPI_Message();
            message.data = _map1 + "{" + _map2 + "{" + _op;
            message.source = "0";
            message.dest = "0";
            mpi.Send(message, "input");
            //mpi.BroadCast(message, "comm_workers");
        }

        public string checkProgress()
        {
            //int finishMessages = 0;
            string rslt = string.Empty;
            CloudQueueMessage msg = new CloudQueueMessage("");
            GPC_Overlay.QueueHelper queue = new GPC_Overlay.QueueHelper(connectionString);
            cMPI mpi = new cMPI(connectionString,"Master");
            List<cMPI_Message> messages = new List<cMPI_Message>();
            cMPI_Message inputMsg = new cMPI_Message();
            if (numMessages == 0)
            {
                if (mpi.Recv(out inputMsg, "0", "input", true))
                {
                    numMessages = int.Parse(inputMsg.data);
                    return numMessages.ToString();
                }
            }
            else
            {
                if (mpi.RecvMult(out messages, 32, "0", "commresult", true))
                {
                    foreach (cMPI_Message message in messages)
                    {
                        results.Add(message.data);
                    }
                    rslt += results.Count.ToString() + " out of " + numMessages.ToString() + " polygons have been processed.";

                    if (results.Count == numMessages)
                    {
                        rslt = _saveResult();
                        processing = true;
                        tmrUpdate.Enabled = false;
                        rslt = "Crayons is done processing files.\n";
                    }
                }
                else
                {
                    rslt += "Crayons is distributing work among workers";
                }
            }
            return rslt;
        }

        private string _saveResult()
        {
            string[] blockIDs;
            int numberOfWorkers = RoleEnvironment.Roles["GISWorkerRole"].Instances.Count;
            string connectionString = RoleEnvironment.GetConfigurationSettingValue("DataConnectionString");
            GPC_Overlay.QueueHelper queue = new GPC_Overlay.QueueHelper(connectionString);

            DateTime startSaveTime = DateTime.Now;
            // Write the end tag for the output ile 
            string outputEndTag = "</gml:FeatureCollection>";
            GPC_Overlay.BlobHelper.PutBlock(connectionString, GPC_Overlay.DataConstants.MAP_CONTAINER_BLOB, GPC_Overlay.DataConstants.OUTPUT_BLOB, Guid.NewGuid().ToString(), outputEndTag);
            // Get the uncommitted blocks 
            GPC_Overlay.BlobHelper.GetBlockList(connectionString, GPC_Overlay.DataConstants.MAP_CONTAINER_BLOB, GPC_Overlay.DataConstants.OUTPUT_BLOB, out blockIDs);
            //Commit the blob 
            GPC_Overlay.BlobHelper.PutBlockList(connectionString, GPC_Overlay.DataConstants.MAP_CONTAINER_BLOB, GPC_Overlay.DataConstants.OUTPUT_BLOB, blockIDs);
            TimeSpan saveTime = DateTime.Now.Subtract(startSaveTime);
            //List<CloudQueueMessage> msgs = new List<CloudQueueMessage>();
            //IEnumerable<CloudQueueMessage> msg = new List<CloudQueueMessage>();

            CloudQueueMessage timeMsg = new CloudQueueMessage("");
            string strTimeMsg = String.Empty;
           
            int MessageCount = numMessages;

            DateTime msgTime = DateTime.Parse(results[0]);
            foreach (string rslt_msg in results)
            {
                if (DateTime.Parse(rslt_msg) > msgTime)
                    msgTime = DateTime.Parse(rslt_msg);
            }

            System.Diagnostics.Trace.WriteLine("Processing ended at " + msgTime.ToString());

            //queue.ClearMessages(GPC_Overlay.DataConstants.RESULT_QUEUE);
            //queue.ClearMessages(GPC_Overlay.DataConstants.INPUT_PARAS);
            //queue.ClearMessages(GPC_Overlay.DataConstants.BLOB_COUNT);
            string rsltStr = "Output Creation time: " + (saveTime.TotalSeconds).ToString() + " Seconds\n";
            System.Diagnostics.Trace.WriteLine(rsltStr);

            return "Download resulting GML file from https://afcrayons.blob.core.windows.net/gpcfiles/result.xml";
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {

            GPC_Overlay.QueueHelper queue = new GPC_Overlay.QueueHelper(connectionString);
            _op = ddlOperator.SelectedValue.ToString();
            _map1 = ddlMap1.SelectedValue.ToString();
            _map2 = ddlMap2.SelectedValue.ToString();

            if (_map1 == String.Empty || _map2 == string.Empty || _op == String.Empty)
            {
                txtTimer.Text = "All fields are required. Please select correct valuses and click submit again.";
            }
            else
            {
                assignWork();
                tmrUpdate.Enabled = true;
                btnSubmit.Visible = false;
            }
        }

        protected void ddlMap1_IndexChanged(object sender, EventArgs e)
        {
            _map1 = (ddlMap1.SelectedIndex != -1) ? ddlMap1.SelectedItem.ToString() : string.Empty;
        }

        protected void ddlOperator_IndexChanged(object sender, EventArgs e)
        {
            if (this.ddlOperator.SelectedIndex != -1)
            {
                _operator = (GpcOperation)Enum.Parse(typeof(GpcOperation), this.ddlOperator.SelectedItem.Value);
            }
            else
            {
                _operator = GpcOperation.Union;
            }
        }

        protected void ddlMap2_IndexChanged(object sender, EventArgs e)
        {
            _map2 = (ddlMap2.SelectedIndex != -1) ? ddlMap2.SelectedItem.ToString() : string.Empty;
        }

        protected void tmrUpdate_Tick(object sender, EventArgs e)
        {
            if (processing != true)
            {
                txtTimer.Text = checkProgress();
            }
            else
            {
                tmrUpdate.Enabled = false;
            }
        }

        protected void cmdReset_Click(object sender, EventArgs e)
        {
            txtTimer.Text = "";
            cmdReset.Visible = false;
            btnSubmit.Visible = true;
        }
    }
}

